package cn.bqjr.eily.samples.facade.impl;

import cn.bqjr.eily.core.annotation.AutoLogable;
import cn.bqjr.eily.samples.common.shiro.KickoutUserAsync;
import cn.bqjr.eily.samples.constants.SysConstant;
import cn.bqjr.eily.samples.entity.po.Menu;
import cn.bqjr.eily.samples.entity.po.User;
import cn.bqjr.eily.samples.entity.po.UserRole;
import cn.bqjr.eily.samples.entity.vo.UserVO;
import cn.bqjr.eily.samples.facade.IUserFacade;
import cn.bqjr.eily.samples.service.base.IMenuService;
import cn.bqjr.eily.samples.service.base.IRoleService;
import cn.bqjr.eily.samples.service.base.IUserRoleService;
import cn.bqjr.eily.samples.service.base.IUserService;
import cn.bqjr.eily.shiro.spring.boot.utils.EncryptUtils;
import cn.bqjr.eily.utils.StringUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigInteger;
import java.util.*;

@Service
public class UserFacade implements IUserFacade {

    private final Logger logger = LoggerFactory.getLogger(UserFacade.class);

    @Autowired
    private IUserService userService;

    @Autowired
    private IUserRoleService userRoleService;

    @Autowired
    private IRoleService roleService;

    @Autowired
    private IMenuService menuService;

    @Autowired
    private KickoutUserAsync userAsync;

    @Override
    public boolean kickoutUserByUserId(Long userId) {
        return true;
    }

    @Override
    public boolean kickoutUserByLoginId(String loginId) {
        return true;
    }

    @Override
    @Transactional
    public boolean lockUser(Long userId) {
        User user = userService.selectById(userId);
        Assert.notNull(user, "用户不存在：" + userId);

        user.setLocked(Boolean.TRUE);
        return userService.updateById(user);
    }

    @Override
    @Transactional
    public boolean unLockUser(Long userId) {
        User user = userService.selectById(userId);
        Assert.notNull(user, "用户不存在：" + userId);

        user.setLocked(Boolean.FALSE);
        return userService.updateById(user);
    }

    @Override
    public boolean unLockLoginRetry(String loginId) {
        return true;
    }

    @Override
    public boolean unLockLoginRetry(Long userId) {
        User user = userService.selectById(userId);
        Assert.notNull(user, "用户不存在：" + userId);

        return true;
    }

    @Override
    @AutoLogable(descp = "获取用户权限")
    public Set<String> selectUserPerms(Long userId) {
        List permQueryList;
        // 查询对象为管理员admin，则返回全部权限
        if (SysConstant.ADMIN_USER_ID == userId.longValue()) {
            permQueryList = menuService.selectObjs(
                    new EntityWrapper<Menu>().setSqlSelect("DISTINCT " + Menu.PERMS).isNotNull(Menu.PERMS));
        } else {
            permQueryList = userService.selectUserPermList(userId);
        }
        Set<String> permSet = new HashSet<>(permQueryList.size());
        permQueryList.stream()
                     .filter(obj -> obj instanceof String)
                     .forEach(obj -> permSet.addAll(Arrays.asList(obj.toString().trim().split(","))));
        return permSet;
    }

    @Override
    public List<Menu> selectUserMenus(Long userId) {
        List<Long> userRoleIdList = selectUserRoleIdList(userId);
        List<Menu> userMenuTree = menuService.fillMenuTree(
                menuService.selectRootMenuByRole(SysConstant.DEFAULT_PARENT_MENU_ID, userRoleIdList, false),
                userRoleIdList,
                false);
        return userMenuTree;
    }

    @Override
    public List<Long> selectUserRoleIdList(Long userId) {
        // 查询对象为管理员admin，则返回全部角色ID
        if (SysConstant.ADMIN_USER_ID == userId.longValue()) {
            return Arrays.asList(SysConstant.ADMIN_ROLE_ID);
        }

        List<Object> objList = userRoleService.selectObjs(
                new EntityWrapper<UserRole>().setSqlSelect(UserRole.ROLEID)
                                             .eq(UserRole.USERID, userId));
        List<Long> roleIdList = new ArrayList<>(objList.size());
        objList.stream()
               .filter(obj -> obj instanceof BigInteger)
               .forEach(obj -> roleIdList.add(((BigInteger) obj).longValue()));

        return roleIdList;
    }

    @Override
    @Transactional
    public boolean insertVO(UserVO userVO) throws Exception {
        userVO.setPassword(EncryptUtils.encrypt(userVO.getPassword(), userVO.getLoginId()));
        User user = new User();
        BeanUtils.copyProperties(userVO, user);
        userService.insert(user); // 新增用户记录

        // 新增用户角色关联记录
        Long userId = user.getUserId();
        List<Long> roleIdList = userVO.getRoleIdList();
        if (!CollectionUtils.isEmpty(roleIdList)) {
            roleIdList.stream().forEach(
                    roleId -> userRoleService.insert(
                            new UserRole().setRoleId(roleId)
                                          .setUserId(userId)));
        }

        return true;
    }

    @Override
    @Transactional
    public boolean updateVO(UserVO userVO) throws Exception {
        Long userId = userVO.getUserId();
        List<Long> roleIdList = userVO.getRoleIdList();

        // 更新用户角色记录
        if (!CollectionUtils.isEmpty(roleIdList)) {
            userRoleService.delete(new EntityWrapper<UserRole>().eq(UserRole.USERID, userId));
            roleIdList.stream()
                      .filter(roleId -> null != roleService.selectById(roleId))
                      .forEach(roleId -> userRoleService.insert(
                              new UserRole().setRoleId(roleId).setUserId(userId)));
            userAsync.kickoutByUserId(userId);
        }

        if (StringUtils.isNotEmpty(userVO.getPassword())) {
            userVO.setPassword(EncryptUtils.encrypt(userVO.getPassword(), userVO.getLoginId()));
        }

        User user = new User();
        BeanUtils.copyProperties(userVO, user);
        userService.updateById(user);

        return true;
    }

    @Override
    @Transactional
    public boolean deleteUser(Long userId) {
        logger.debug("删除用户表信息...");
        userService.deleteById(userId);

        logger.debug("删除用户角色关联表信息...");
        userRoleService.delete(new EntityWrapper<UserRole>().eq(UserRole.USERID, userId));
        userAsync.kickoutByUserId(userId);

        return true;
    }

    @Override
    @Transactional
    public boolean deleteUserByBatchId(List<Long> userIds) {
        userIds.stream().forEach(userId -> {
            deleteUser(userId);
            userAsync.kickoutByUserId(userId);
        });
        return true;
    }
}
